#!/usr/bin/env python

import time
import model
import datetime
import restclient
import resource.string.app

from .._config import Config
from .._console import Console

class Uploader(Console):

    def run(self):
        self.greeting(resource.string.app)
        
        name = resource.string.app.name
        if self.stopped:
            self.info('%s is stopped.\n' % name)
            self.info('You must resume first.\nSee help for more info.\n')
        else:
            if self.init():
                self.info('SMS uploader started.\n\n')
                
                self._db = self.openDb()
                inboxes = self.load()
                self.upload(inboxes)
                if self._db.dirty:
                    self.progress('Saving database... ')
                    self._db.commit()
                    self.success('OK ^_^v\n')
                
                self.info('\nSMS uploader finished.\n')
        
        self.farewell()

    def init(self):
        config = Config()
        
        try:
            host = config.get('Rest', 'Host')
            self.verbose('Rest Host: %s\n' % host)
        except:
            self.fail('Rest host is not set.\n'
                      'Please create [Rest] Host entry in the config.\n')
            return False
        
        self._rest = {}
        self._rest['host'] = host
        
        return True
    
    def stop(self, message):
        self.progress('Set stop flag... ')
        if super(Uploader, self).stop():
            self.success('OK ^_^v')
        else:
            self.fail('Error >_<')
        self.notify(message)
        
    def load(self):
        condition = model.sa.and_(model.Message.uploaded == None,
                                  model.Message.sequence == 1)
        query = self._db.query(model.Message)
        return query.filter(condition).all()

    def upload(self, inboxes):
        total = len(inboxes)
        self.info('Found %s SMS.\n' % total)
        uploading = 'Uploading SMS {:,} of {:,}... '
        timedelta = datetime.timedelta(hours=7)
        counter = 0
        for inbox in inboxes:
            if self.stopped: break
            
            counter += 1
            if inbox.total == 1:
                message = inbox.message
            else:
                self.info('Long SMS detected.\n')
                self.progress('Rebuilding message... ')
                message = self.rebuild(inbox)
                if message:
                    self.success('OK ^_^v\n')
                else:
                    self.fail('Error >_<\n')
                    self.info('Continuing to next SMS.\n')
                    continue
                
            self.progress(uploading.format(counter, total))
            self.verbose('Sender: %s' % inbox.sender)
            self.verbose('Message:\n%s\n' % message)
            dateTime = inbox.dateTime + timedelta
            if dateTime > datetime.datetime.now() + datetime.timedelta(hours=4):
                dateTime = inbox.dateTime
            timestamp = time.mktime(dateTime.timetuple())
            params = {'dateTime': timestamp, 'contact': inbox.sender,
                      'value': message}
            action = 'api/sms'
            responses = self.restPost(action, params)
            if responses[0]['status'] == 200:
                self.success('OK ^_^v\n')
                inbox.uploaded = 1
            else:
                self.fail('Error >_<\n')
                self.stop('Rest post command failed.\n'
                          'Command: %s\n'
                          'Params: %s\n\n'
                          'Karin stopped.' % (action, params))
                inbox.uploaded = 0
            
    def rebuild(self, inbox):
        '''Rebuild long SMS.
        
        Sometimes long SMS comes in random order, so check all SMS with the same
        reference and sender in the period of 1 hour.'''
        
        timedelta = datetime.timedelta(hours=8)
        start = inbox.dateTime - timedelta
        finish = inbox.dateTime + timedelta
        condition = model.sa.and_(model.Message.dateTime >= start,
                                  model.Message.dateTime <= finish,
                                  model.Message.decompiled == 1,
                                  model.Message.reference == inbox.reference)
        query = self._db.query(model.Message).order_by(model.Message.sequence)
        inboxes = query.filter(condition)
        if inboxes.count() != inbox.total:
            timedelta = datetime.timedelta(hours=8)
            deadline = inbox.dateTime + timedelta
            if datetime.datetime.now() < deadline:
                return False
                
        return u''.join([inbox.message for inbox in inboxes])
        
    def evalRestResponse(self, responses):
        self.verbose('Rest Responses[0]: %s' % responses[0])
        self.verbose('Rest Responses[1]: %s\n' % responses[1])
        
        responses[0]['status'] = int(responses[0]['status'])
        try: data = json.loads(responses[1])
        except:
            return (responses[0], responses[1])
        
        try:
            message = json.loads(data['message'])
            data['message'] = message
        except: pass
        return (responses[0], data)
    
    def restPost(self, action, params):
        url = 'http://%s/%s' % (self._rest['host'], action)
        
        self.verbose('Rest Post: %s' % url)
        self.verbose('Params: %s' % params)
        
        responses = restclient.POST(url, params, async=False, resp=True)
        return self.evalRestResponse(responses)
